package com.pig4cloud.pigx.contract.websocket.subscribe;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pig4cloud.pigx.contract.vo.AbstractTopicVO;
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
import org.springframework.util.CollectionUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 */
public abstract class RankingAbstractTopic {

	protected String TOPICNAME = "";
	public Map<WebSocketSession, List<AbstractTopicVO>> subList = new ConcurrentHashMap<>();

	/**
	 * 将参数添加到订阅列表
	 *
	 * @param session  会话
	 * @param newParam 新参数
	 * @since 2022/9/25 17:34
	 */
	protected void add(WebSocketSession session, AbstractTopicVO newParam) {
		// 用户没有订阅过，直接加入订阅列表
		if (!this.subList.containsKey(session)) {
			List<AbstractTopicVO> list = new ArrayList<>(2);
			list.add(newParam);
			this.subList.put(session, list);
			return;
		}

		// 订阅过的参数集合
		List<AbstractTopicVO> oldParamList = this.subList.get(session);
		// 新参数
		List<String> newDataList = newParam.getDataList();
		// 是否存在重复的查询条件
		boolean hasConflict = false;
		for (AbstractTopicVO oldParam : oldParamList) {
			// 比较新旧参数
			List<String> oldDataList = oldParam.getDataList();

			// 如果数量不一致，直接结束当前对比
			if (newDataList.size() != oldDataList.size()) {
				continue;
			}

			// 比较新旧参数的值是否完全一致
			boolean allEquals = true;
			for (int i = 0; i < newDataList.size(); i++) {
				String newData = newDataList.get(i);
				String oldData = oldDataList.get(i);

				// 如果有任意参数不一致
				if (!Objects.equals(newData, oldData)) {
					allEquals = false;
					break;
				}
			}

			// 如果参数完全一致
			if (allEquals) {
				hasConflict = true;
				break;
			}
		}

		// 不存在重复的查询条件
		if (!hasConflict) {
			oldParamList.add(newParam);
		}
	}

	/**
	 * 将参数移出订阅列表
	 *
	 * @param session 会话
	 * @param param   需要移除的参数
	 * @since 2022/9/25 17:35
	 */
	protected void remove(WebSocketSession session, AbstractTopicVO param) {
		// 订阅过的参数集合
		List<AbstractTopicVO> oldParamList = this.subList.get(session);
		// 如果参数集合已经为空，移除该会话
		if (CollectionUtils.isEmpty(oldParamList)) {
			this.subList.remove(session);
			return;
		}

		// 新参数
		List<String> newDataList = param.getDataList();
		// 是否存在重复的查询条件
		boolean hasConflict = false;
		for (int i = 0; i < oldParamList.size(); i++) {
			AbstractTopicVO oldParam = oldParamList.get(i);
			// 比较新旧参数
			List<String> oldDataList = oldParam.getDataList();

			// 如果数量不一致，直接结束当前对比
			if (newDataList.size() != oldDataList.size()) {
				continue;
			}

			// 比较新旧参数的值是否完全一致
			boolean allEquals = true;
			for (int j = 0; j < newDataList.size(); j++) {
				String newData = newDataList.get(j);
				String oldData = oldDataList.get(j);

				// 如果有任意参数不一致
				if (!Objects.equals(newData, oldData)) {
					allEquals = false;
					break;
				}
			}

			// 如果参数完全一致，删除该参数
			if (allEquals) {
				hasConflict = true;
				oldParamList.remove(i);
				break;
			}
		}

		// 删除参数后，参数集合为空，移除该会话
		if (hasConflict && CollectionUtils.isEmpty(oldParamList)) {
			this.subList.remove(session);
		}
	}

	/**
	 * 订阅
	 *
	 * @param session 会话
	 * @param params  参数
	 * @since 2022/9/25 17:34
	 */
	public AbstractTopicVO sub(WebSocketSession session, List<String> params) {
		// 转换参数为vo
		AbstractTopicVO vo = new AbstractTopicVO();
		vo.setDataList(params);

		// 将参数添加到订阅列表
		add(session, vo);
		return vo;
	}

	/**
	 * 取消订阅
	 *
	 * @param session 会话
	 * @param params  参数
	 * @since 2022/9/25 17:42
	 */
	public void unsub(WebSocketSession session, List<String> params) {
		// 转换参数为vo
		AbstractTopicVO vo = new AbstractTopicVO();
		vo.setDataList(params);

		// 将参数移出订阅列表
		remove(session, vo);
	}

	public TextMessage getTextMessage(Object type, Object data) {
		JSONObject object = new JSONObject();
		object.put("params", type);
		object.put("data", data);
		try {
			ObjectMapper objectMapper = new ObjectMapper();
			String asString = objectMapper.writeValueAsString(object);
			return new TextMessage(asString);
		} catch (Exception e) {
			return new TextMessage(object.toJSONString());
		}
	}
}
